#pragma once
#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "common.hpp"
#include "log.hpp"
#include "Intaddr.hpp"
#include <functional>
#include "ThreadPool.hpp"

using namespace LogModule;
using namespace ThreadPoolModule;

const static uint16_t gdefaultport = 8080;
const static int gsockfd = -1;

using adduser_t = std::function<void(InetAddr &id)>;
using remove_t =std::function<void(InetAddr& id)>;
using task_t = std::function<void()>;                                        // 线程池需要的任务
using route_t = std::function<void(int sockfd, const std::string &message)>; // 在类内部要设置的路由的回调方法

class UdpServer
{
public:
    UdpServer(uint16_t port = gdefaultport)
        : _netaddr(port),
          _sockfd(gsockfd),
          _isrunning(false)
    {
    }

    void InitServer()
    {
        // 1.创建socket文件
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); // 没有Int  这里如果定义了一个变量  _sockfd的值就是没有变化的
        if (_sockfd < 0)                            // 加 int 会变成局部变量，导致成员变量未被修改。
        {
            LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
            Die(SOCKET_ERR);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;

        // 2.填充网络信息并bind
        //  struct sockaddr_in local;
        //  bzero(&local, sizeof(local));//先置零
        //  local.sin_family = AF_INET;
        //  local.sin_port = ::htons(_port); // 要被发送给对方的，即要发到网络中！
        //  // local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 服务器ip不用绑定 1. string ip->4bytes 2. network order //TODO
        //  local.sin_addr.s_addr = INADDR_ANY;

        // bind
        int n = ::bind(_sockfd, _netaddr.NetAddr(), _netaddr.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind success";
    }

    void RegisterServer(adduser_t adduser,remove_t remove, route_t route)
    {
        _adduser_t = adduser;
        _remove_t =remove;
        _route_t = route;
    }

    void Start()
    {
        _isrunning = true;
        // 服务器启动一直运行
        while (true)
        {
            // 缓冲区和输出型参数
            char inbuffer[1024]; // string
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            // 服务器收信息
            ssize_t n = ::recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, CONV(&client), &len);
            if (n > 0)
            {
                std::cout << "我已收到" << std::endl;

                // 1. 消息内容 && 2. 谁发给我的

                // 16位网络数据 → 主机字节序(大端/小端)
                //  uint16_t clientport = ::ntohs(client.sin_port);
                //  //将二进制网络字节序的 IP 地址转换为可读的字符串格式
                //  char ip[64];
                //  const char* clientip = ::inet_ntop(AF_INET, &client.sin_addr , ip , sizeof(ip));
                InetAddr netclient(client);
                inbuffer[n] = 0;
                std::string message;
                if(strcmp(inbuffer ,"QUIT") == 0)
                {
                    //移除观察者
                    _remove_t(netclient);
                    message =netclient.Addr()+"#"+"我走了 ,你们聊";
                    
                }
                else
                {
                     // 2.新增客户
                    _adduser_t(netclient);
                    message= netclient.Addr()+"#"+inbuffer;
                }


                // 3.消息转发 构建转发任务,推送给线程池 ,让线程池转发
                //固定绑定两个参数
                task_t task = std::bind(UdpServer::_route_t, _sockfd, message); //_route_t不是成员方法 ,是函数对象,不用加this?
                ThreadPool<task_t>::getInstance()->Enqueue(task);

                // std::string clientinfo =netclient.IP()  + ":" + std::to_string(netclient.Port()) + " # " + inbuffer;
                // LOG(LogLevel::DEBUG) << clientinfo;

                // std::string echo_string = "echo# ";
                // echo_string += inbuffer;

                // ssize_t num_bytes =::sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, CONV(&client), len);
                // if(num_bytes < 0)
                // {
                //     LOG(LogLevel::FATAL) << "sendto: " << strerror(errno);
                //     Die(SERVER_SEND_ERR);
                // }
            }
        }
        _isrunning = false;
    }

    ~UdpServer()
    {
        if (_sockfd > gsockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;
    // uint16_t _port;
    InetAddr _netaddr;
    bool _isrunning;

    // 新增用户
    adduser_t _adduser_t;
    //移除用户
    remove_t _remove_t;

    // 发送消息
    route_t _route_t;

};

// class UdpServer
// {
// public:
//     UdpServer(uint16_t port = gdefaultport)
//         : _port(port),
//           _sockfd(gsockfd),
//           _isrunning(false)
//     {
//     }

//     void InitServer()
//     {
//         //1.创建socket文件
//         _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0); //没有Int  这里如果定义了一个变量  _sockfd的值就是没有变化的
//         if (_sockfd < 0)                            //加 int 会变成局部变量，导致成员变量未被修改。
//         {
//             LOG(LogLevel::FATAL) << "socket: " << strerror(errno);
//             Die(SOCKET_ERR);
//         }
//         LOG(LogLevel::INFO) << "socket success, sockfd is : " << _sockfd;

//         //2.填充网络信息并bind
//         struct sockaddr_in local;
//         bzero(&local, sizeof(local));//先置零
//         local.sin_family = AF_INET;
//         local.sin_port = ::htons(_port); // 要被发送给对方的，即要发到网络中！
//         // local.sin_addr.s_addr = ::inet_addr(_ip.c_str()); // 服务器ip不用绑定 1. string ip->4bytes 2. network order //TODO
//         local.sin_addr.s_addr = INADDR_ANY;

//         //bind
//         int n = ::bind(_sockfd , CONV(&local) , sizeof(local));
//         if (n < 0)
//         {
//             LOG(LogLevel::FATAL) << "bind: " << strerror(errno);
//             Die(BIND_ERR);
//         }
//         LOG(LogLevel::INFO) << "bind success";

//     }

//     void Start()
//     {
//         _isrunning=true;
//         //服务器启动一直运行
//         while(true)
//         {
//             //缓冲区和输出型参数
//             char inbuffer[1024]; // string
//             struct sockaddr_in client;
//             socklen_t len = sizeof(client);

//             //服务器收信息
//             ssize_t n = ::recvfrom(_sockfd ,inbuffer ,sizeof(inbuffer)-1 ,0 ,CONV(&client) , &len);
//             if (n > 0)
//             {
//                 std::cout<<"我已收到"<<std::endl;
//                 // 1. 消息内容 && 2. 谁发给我的
//                 //16位网络数据 → 主机字节序(大端/小端)
//                 uint16_t clientport = ::ntohs(client.sin_port);
//                 //将二进制网络字节序的 IP 地址转换为可读的字符串格式
//                 char ip[64];
//                 const char* clientip = ::inet_ntop(AF_INET, &client.sin_addr , ip , sizeof(ip));
//                 inbuffer[n] = 0;

//                 std::string clientinfo = std::to_string(clientport) + ":" + clientip + " # " + inbuffer;
//                 LOG(LogLevel::DEBUG) << clientinfo;

//                 std::string echo_string = "echo# ";
//                 echo_string += inbuffer;

//                 ssize_t num_bytes =::sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, CONV(&client), len);
//                 if(num_bytes < 0)
//                 {
//                     LOG(LogLevel::FATAL) << "sendto: " << strerror(errno);
//                     Die(SERVER_SEND_ERR);
//                 }
//                 std::cout<<"我已发出"<<std::endl;

//             }

//         }
//         _isrunning=false;

//     }

//     ~UdpServer()
//     {
//         if(_sockfd > gsockfd)
//             ::close(_sockfd);
//     }

// private:
//     int _sockfd;
//     uint16_t _port;
//     bool _isrunning;
// };
